#include "enigma.h"
#include "rotor.h"

#include <QDebug>

Enigma::Enigma() :
    m_rotors{nullptr},
    m_plugboard(nullptr),
    m_reflector(nullptr),
    m_rotateFirst(false)
{

}

Enigma::~Enigma()
{
    for (int i = 0; i < ROTORS_MAX_NUMB; i++) {
        if (m_rotors[i] != nullptr) {
            delete m_rotors[i];
        }
    }
    if (m_plugboard != nullptr) {
        delete m_plugboard;
    }
    if (m_reflector != nullptr) {
        delete m_reflector;
    }
}

void Enigma::installRotor(int pos, Rotor *rotor)
{
    if (pos >= ROTORS_MAX_NUMB || pos < 0) return;

    if (m_rotors[pos] != nullptr) {
        delete m_rotors[pos];
    }
    m_rotors[pos] = rotor;
    if (pos != 0) {
        m_rotors[pos-1]->setRotorNext(m_rotors[pos]);
    }
    if (pos != (ROTORS_MAX_NUMB-1)) {
        m_rotors[pos]->setRotorNext(m_rotors[pos+1]);
    }
}

void Enigma::installPlugboard(Plugboard *plugboard)
{
    if (m_plugboard != nullptr) {
        delete m_plugboard;
    }
    m_plugboard = plugboard;
}

void Enigma::installReflector(Reflector *reflector)
{
    if (m_reflector != nullptr) {
        delete m_reflector;
    }
    m_reflector = reflector;
}

void Enigma::setStartPhase(const QString &start)
{
    if (start.length() > ROTORS_MAX_NUMB) return;

    for (int i = 0; i < ROTORS_MAX_NUMB; i++) {
        if (m_rotors[i] != nullptr) {
            m_rotors[i]->setRotorPhase(start.at(i).toLatin1());
        }
    }
    m_startPhase = start;
}

void Enigma::reset()
{
    for (int i = 0; i < ROTORS_MAX_NUMB; i++) {
        if (m_rotors[i] != nullptr) {
            m_rotors[i]->setRotorPhase(m_startPhase.at(i).toLatin1());
        }
    }
}

char Enigma::encryptChar(char ch)
{
    if (m_plugboard == nullptr) {
        return ch;
    }
    if (m_reflector == nullptr) {
        return ch;
    }
    if (ch >= 'A' && ch <= 'Z') {

    } else if (ch >= 'a' && ch <= 'z') {
        ch += 'a' - 'A';
    } else {
        return ch;
    }

    if (m_rotateFirst) {
        m_rotors[0]->rotate();
    }

    ch = m_plugboard->getRotorChar(ch);

    for (int i = 0; i < ROTORS_MAX_NUMB; i++) {
        Rotor *it = m_rotors[i];
        if (it == nullptr) break;
        ch = it->getRotorChar(ch);
    }

    ch = m_reflector->getRotorChar(ch);

    for (int i = (ROTORS_MAX_NUMB-1); i >= 0; i--) {
        Rotor *it = m_rotors[i];
        if (it == nullptr) continue;
        ch = it->getRotorCharReversed(ch);
    }

    ch = m_plugboard->getRotorChar(ch);

    if (!m_rotateFirst) {
        m_rotors[0]->rotate();
    }

    return ch;
}

QString Enigma::encryptText(const QString &text)
{
    QString cipherStr;

    foreach (auto ch, text) {
        ch = encryptChar(ch.toLatin1());
        cipherStr.append(ch);
    }

    return cipherStr;
}

void Enigma::enableRotateFirst(bool enable)
{
    m_rotateFirst = enable;
}
